/**
 * Una clase para crear graficos de google sin importar el tipo.
 * Nota: Esta clase asume que se ha cargado la libreria de google correspondiente
 * @see google.load()
 */
function GoogleChartFactory(){
    /**
     * Este metodo insancia un grafico de google del tipo especificado
     * 
     * @param type - una cadena que indica el tipo de grafico requerido.
     *               Tipos soportados: - "geo" que instancia un GeoMap.
     *                                 - "bar" que instancia un BarChart.
     *                                 - "column" que instancia un ColumnChart.
     *                                 - "pie" que instancia un PieChart.
     * @param placeHolder - Un nodo DOM donde se alojara el grafico.
     */
    this.create = function(type, placeHolder){
        return this.chartTypes[type](placeHolder);
    }

    /**
     * Array de metodos que instancian los graficos.
     */
    this.chartTypes = [];
    this.chartTypes["geo"] = function(placeHolder){
        return new google.visualization.GeoMap(placeHolder);
    }
    this.chartTypes["bar"] = function(placeHolder){
        return new google.visualization.BarChart(placeHolder);
    }
    this.chartTypes["column"] = function(placeHolder){
        return new google.visualization.ColumnChart(placeHolder);
    }
    this.chartTypes["motion"] = function(placeHolder){
        return new google.visualization.MotionChart(placeHolder);
    }
    this.chartTypes["pie"] = function(placeHolder){
        return new google.visualization.PieChart(placeHolder);
    }
}

/**
 * Clase que encapsula la construcción de un googleChart y que requiere
 * unicamente un objeto.
 * 
 *@param config - un objeto con el siguiente formato:
	{
		//[Opcional] un nombre para el gráfico. Util para depuracion o indexacion.
		name: "some name",
		// Cadena que indica el tipo de gráfico que se ha de construir, para mas detalles vea: GoogleChartFactory.create();
		type: "bar", 
		// Definicion de las columnas, una array de objetos con las propiedades 'name' y 'type'
		// donde type es una cadena que indica un tipo de dato soportado por googleCharts.
		columns: [
		  {name:"NombreColumna", type:"string"},
		  {name:"NombreColumna2", type:"number"}
		],	
		//Un array bidimensional con los datos listos para construir la dataTable.	
		//Los valores deben tener el mismo formato que su correspondiente columna.
		rows: [
		  ["valor1", 1],
		  ["valor2", "2"] // Los numeros que vienen como cadenas seran convertidos.
		],	
		//Elemento en el que se alojará el gráfico. Debe ser un objeto DOM
		placeHolder: elementoDOM,	
		//[Opcional] Un array de objetos que indican el nombre del evento y 
		//el método que se llamará cuando ocurra. 
		//Para conocer los tipos de eventos soportados y la estructura de sus
		//auditores vea la documentación del gráfico.
		events: [
		  {name: "select", callback: function(){} }
		],
		//[Opcional] Un objeto que indica las caracteristicas visuales del
		//gráfico. 
		// Ver opciones de configuracion del grafico.
		drawOps: {
		} 
	}
 */
function Chart(config){

    this.name = (typeof config.name != 'undefined' ? config.name : "unknown"); //Sin usar, tal vez en algun futuro.
    this.type = (typeof config.type != 'undefined' ? config.type : "bar");
    this.columns = (typeof config.columns != 'undefined' ? config.columns : []);
    this.rows = (typeof config.rows != 'undefined' ? config.rows : []);
    this.placeHolder = (typeof config.placeHolder != 'undefined' ? config.placeHolder : document.body);
    this.events = (typeof config.events != 'undefined' ? config.events : []);
    this.drawOps = config.drawOps;
	
	//Los objetos de googleChart.
    this.gChart = null;
    this.dataTable = null;

    this.toString = function(){
      var str = "";
      str += "Name: " + this.name + "<br />";
      str += "Type: " + this.type + "<br />";
      str += "Columns: " + this.columns + "<br />";
      str += "Rows: " + this.rows + "<br />";
      str += "Events: " + this.events + "<br />";
      str += "DrawOps: " + this.drawOps + "<br />";
      str += "PlaceHolder: " + this.placeHolder + "<br />";

      return str;
    }

    /**
     * Proceder a armar el grafio.
     */
    this.build = function(){
        
        this.dataTable = new google.visualization.DataTable();

        //Crear el grafico adecuado.
        factory = new GoogleChartFactory();
        this.gChart = factory.create(this.type, this.placeHolder);

        //Agregar las columnas
        for(i in this.columns){
            this.dataTable.addColumn(this.columns[i].type, this.columns[i].name);
        }

        //Agregar las filas.
        for(i in this.rows){
            row = [];
            for(j in this.rows[i]){
                row[j] = this.columns[j].type == "string" ? this.rows[i][j] : parseFloat(this.rows[i][j]);
            }
            
            this.dataTable.addRow(row);
        }

        //Agregar los uditores de eventos.
        for(i in this.events){
            google.visualization.events.addListener(this.gChart, this.events[i].name, this.events[i].callback);
        }

    };
    this.build();//Llama al metodo que empaqueta todo.
    
    this.draw = function(){
        this.gChart.draw(this.dataTable, this.drawOps);
    }

}

/**
 * Recibe un array bidimensional y le hace la transpuesta
 * Devuelve un nuevo array
 */
function transpuesta(array){
    transpuesto = [];
    for(i in array){
        for(j in array[i]){
            if(i == 0)
                transpuesto[j] = [];
            transpuesto[j][i] = array[i][j];
        }
    }
    
    return transpuesto;
}

function isArray(obj) {
   return (obj.constructor.toString().indexOf("Array") == -1);
}

function arrayToString(array){
    s = "";
    for(i in array){
        s += i + ": "
        if(isArray(array[i]))
            s += print_r(array[i]);
        else
            s += array[i];

        s += "<br />";
    }

    return s;
}

